import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/base/vehicle_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/scooter_real_time_info.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class RsVeloAllRealTimeInfo extends ScooterAllRealTimeInfo {
  RsVeloAllRealTimeInfo(RsVeloRealTimeInfo realTimeInfo,
      RsVeloRealTimeState realTimeState, RsVeloRealTimeError realTimeError)
      : super(realTimeInfo, realTimeState, realTimeError);
}

class RsVeloVehicleSynthesizeRealTimeInfo extends VehicleSynthesizeRealTimeInfo<CommonVehicleRealTimeInfo, RsVeloRealTimeState, RsVeloRealTimeError> {
  RsVeloVehicleSynthesizeRealTimeInfo(CommonVehicleRealTimeInfo commonVehicleRealTimeInfo, RsVeloRealTimeState realTimeState, RsVeloRealTimeError realTimeError) : super(commonVehicleRealTimeInfo, realTimeState, realTimeError);
}

class RsVeloRealTimeInfo extends ScooterRealTimeInfo {
  Int8 mos1Temp = Int8.zero;
  Int8 mos2Temp = Int8.zero;

  Int8 motor1Temp = Int8.zero;
  Int8 motor2Temp = Int8.zero;

  Int16 busCurrent1 = Int16.zero;
  Int16 busCurrent2 = Int16.zero;

  Int16 phaseCurrent1 = Int16.zero;
  Int16 phaseCurrent2 = Int16.zero;

  Int16 acc = Int16.zero;

  RsVeloRealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = DefaultsVeloRealTimeInfoCompact();
  }

  @override
  String toString() {
    return '${super.toString()}, RsVeloRealTimeInfo{mos1Temp: $mos1Temp, mos2Temp: $mos2Temp, motor1Temp: $motor1Temp, motor2Temp: $motor2Temp, busCurrent1: $busCurrent1, busCurrent2: $busCurrent2, phaseCurrent1: $phaseCurrent1, phaseCurrent2: $phaseCurrent2, acc: $acc}';
  }
}

class DefaultsVeloRealTimeInfoCompact extends Compact<RsVeloRealTimeInfo> {
  @override
  void fromBytes(
      RsVeloRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output.voltage = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.current = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.speed = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.mileage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.remainderRange = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.totalMileage = ByteUtil.bytes2Uint32Le(bytes, offset);
    offset += 4;
    output.batteryLevel =
        Uint16(ByteUtil.bytes2Uint8Le(bytes, offset).value * 100);
    offset++;
    output.mos1Temp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.mos2Temp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.mosTemp = output.mos1Temp.value > output.mos2Temp.value
        ? output.mos1Temp
        : output.mos2Temp;
    output.motor1Temp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.motor2Temp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.batteryTemp =
        ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.busCurrent1 = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.busCurrent2 = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.phaseCurrent1 = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.phaseCurrent2 = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.acc = ByteUtil.bytes2Int16Le(bytes, offset);
  }

  @override
  int length() {
    return 30;
  }
}

class RsVeloRealTimeState extends ScooterRealTimeState {
  Uint4 driveModeState = Uint4.zero;

  static const driveModeFrontMotor = 0;
  static const driveModeRearMotor = 1;
  static const driveModeDualMotor = 2;

  RsVeloRealTimeState(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultLRsVeloRealTimeStateCompact();
  }

  @override
  String toString() {
    return '${super.toString()}, LR1RealTimeState{driveModeState: $driveModeState}';
  }
}

class _DefaultLRsVeloRealTimeStateCompact extends DefaultRealTimeStateCompact {
  @override
  void fromBytes(
      ScooterRealTimeState output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + length()) {
      return;
    }
    super.fromBytes(output, bytes, offset);
    output as RsVeloRealTimeState;
    offset++;
    // 2bit
    output.driveModeState = ByteUtil.bitValue(bytes[offset], 1, 2);
    // 剩余5bit保留
  }

  @override
  int length() {
    return 2;
  }
}

class RsVeloRealTimeError extends ScooterRealTimeError {
  Uint4 controller1State = Uint4.zero;
  Uint4 controller2State = Uint4.zero;

  Uint4 motor1HallState = Uint4.zero;
  Uint4 motor2HallState = Uint4.zero;

  Uint4 hmicMc1ComState = Uint4.zero;
  Uint4 hmicMc2ComState = Uint4.zero;

  Uint4 mcHmicComState = Uint4.zero;

  Uint4 mos1OverTempState = Uint4.zero;
  Uint4 mos2OverTempState = Uint4.zero;

  Uint4 motor1OverTempState = Uint4.zero;
  Uint4 motor2OverTempState = Uint4.zero;

  Uint4 mcu1OverTemp = Uint4.zero;
  Uint4 mcu2OverTemp = Uint4.zero;

  Uint4 hw1OverCurrent = Uint4.zero;
  Uint4 hw2OverCurrent = Uint4.zero;

  Uint4 motor1BlockState = Uint4.zero;
  Uint4 motor2BlockState = Uint4.zero;

  Uint4 imuSensorState = Uint4.zero;
  Uint4 postureErrorState = Uint4.zero;

  Uint4 forceDfuState = Uint4.zero;

  Uint4 errorCloudBox = Uint4.zero;

  RsVeloRealTimeError(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = DefaultVeloRealTimeErrorCompact();
  }

  @override
  bool hasVisibleError() {
    return controller1State.value != 0 ||
        controller2State.value != 0 ||
        batteryState.value != 0 ||
        breakState.value != 0 ||
        throttleState.value != 0 ||
        hmicMc1ComState.value != 0 ||
        hmicMc2ComState.value != 0 ||
        mcHmicComState.value != 0 ||
        imuSensorState.value != 0;
  }

  @override
  bool hasVisibleWarning() {
    return voltageState.value != 0 ||
        mos1OverTempState.value != 0 ||
        mos2OverTempState.value != 0 ||
        motor1OverTempState.value != 0 ||
        motor2OverTempState.value != 0 ||
        overBatteryTempState.value != 0 ||
        mcu1OverTemp.value != 0 ||
        mcu2OverTemp.value != 0 ||
        hw1OverCurrent.value != 0 ||
        hw2OverCurrent.value != 0 ||
        motor1BlockState.value != 0 ||
        motor2BlockState.value != 0 ||
        postureErrorState.value != 0;
  }
}

class DefaultVeloRealTimeErrorCompact extends Compact<RsVeloRealTimeError> {
  @override
  void fromBytes(
      RsVeloRealTimeError output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + length()) {
      return;
    }
    output.originalValue = ByteUtil.bytes2Int32Le(bytes, offset);

    output.controller1State = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.controller2State = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.motor1HallState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.motor2HallState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.batteryState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.voltageState = ByteUtil.bitValue(bytes[offset], 5, 2);
    output.breakState = ByteUtil.bitValue(bytes[offset], 7, 1);

    offset++;
    output.throttleState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.hmicMc1ComState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.hmicMc2ComState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.mcHmicComState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.mos1OverTempState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.mos2OverTempState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.motor1OverTempState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.motor2OverTempState = ByteUtil.bitValue(bytes[offset], 7, 1);

    offset++;
    output.overBatteryTempState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.mcu1OverTemp = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.mcu2OverTemp = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.hw1OverCurrent = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.hw2OverCurrent = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.motor1BlockState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.motor2BlockState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.imuSensorState = ByteUtil.bitValue(bytes[offset], 7, 1);

    offset++;
    output.postureErrorState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.forceDfuState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.errorCloudBox = ByteUtil.bitValue(bytes[offset], 2, 1);
    // 保留5bit
  }

  @override
  int length() {
    return 4;
  }
}
